home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp95 / freyja13.exe / lha / BUF.C < prev    next >
C/C++ Source or Header  |  1992-03-22  |  45KB  |  2,043 lines

  1. /* BUF.C -- Buffer Managment
  2.  
  3.     Written March 1991 by Craig A. Finseth
  4.     Copyright 1991 by Craig A. Finseth
  5. */
  6.  
  7. #include "freyja.h"
  8.  
  9. #ifdef UNIX
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #endif
  13.  
  14. #define ZCK    '\013'        /* ^K */
  15.  
  16. struct phys_page {
  17.     char page_data[PAGESIZE];    /* the page */
  18.     struct phys_page *next;        /* LRU chain */
  19.     struct phys_page *prev;
  20.     char page_loc;            /* logical location of page */
  21.     int page_num;
  22.     FLAG is_mod;            /* is the page dirty? */
  23.     struct virt_page *pptr;        /* page description for this page */
  24.     };
  25.  
  26.  
  27.     /* cached information on the current page */
  28. static struct virt_page *cur_page;    /* virtual page */
  29. static int cur_pt_offset;        /* point offset */
  30. static int cur_page_len;        /* page length */
  31. static char *cur_cptr;            /* actual character */
  32. static char *cur_page_start;        /* start of the page */
  33. static char *cur_gap_start;        /* position of the gap */
  34. static char *cur_gap_end;
  35. static FLAG cur_is_mod;            /* is modified (dirty) */
  36. static int cur_col = -1;        /* current column position */
  37.  
  38. static int savecol;
  39. struct mark *getmark;
  40.  
  41. static struct mark marks[MAXMARK];
  42. #define MAXSMARK    (sizeof(screenmarks) / sizeof(screenmarks[0]))
  43. static struct mark screenmarks[ROWMAX + 2];
  44.  
  45. #if defined(MSDOS)
  46. static int swap_base;
  47. #else
  48. static char *swap_base;
  49. #endif
  50.  
  51. static struct phys_page pages[NUM_PHYS_PAGES];    /* page descriptors */
  52.  
  53. static struct phys_page *first_phys_page;  /* LRU chain of pages in memory */
  54. static struct phys_page *last_phys_page;
  55.  
  56. #define SWAPMAPSIZE    ((long)SWAPMAX * 1024 / PAGESIZE)
  57. static char swap_map[SWAPMAPSIZE];    /* swap file in use flags */
  58. static int num_swap;            /* number of swap file pages */
  59.  
  60.  
  61.  
  62. void B_FileReadCheck();        /* void */
  63. void B_GetGap();        /* void */
  64. int B_IndexB();            /* char *array, int len, char chr */
  65. int B_IndexF();            /* char *array, int len, char chr */
  66. FLAG B_InsChar();        /* char new */
  67. void B_MarkUpdate();        /* struct virt_page *new_page, int amt,
  68.                 int new_offset */
  69. void B_MarkUpdateNP();        /* struct virt_page *new_page,
  70.                 int new_offset */
  71. void B_MovePointTo();        /* int dist */
  72. struct virt_page * B_PageAllocate();    /* struct buffer *bptr;
  73.             struct virt_page *prev, struct virt_page *next */
  74. struct phys_page *B_PageFindFree();    /* void */
  75. void B_PageFree();        /* struct buffer *bptr,
  76.                 struct virt_page *pptr */
  77. FLAG B_PageSplit();        /* int amount */
  78. void B_PageToMemory();        /* struct virt_page *pptr */
  79. void B_PageToCurrent();        /* struct virt_page *pptr */
  80. void B_RulerLine();        /* void */
  81. void B_SetScreenMarks();    /* FLAG newflag */
  82. void B_SetScreenMarks2();    /* struct window *wptr, FLAG newflag */
  83.  
  84. /* ------------------------------------------------------------ */
  85.  
  86. /* Initialize the buffer abstraction.  Return TRUE on success or FALSE
  87. on failure. */
  88.  
  89. FLAG
  90. BInit(swap_size)
  91.     int swap_size;
  92.     {
  93.     struct phys_page *pptr;
  94.     int cnt;
  95.  
  96.     cbuf = NULL;
  97.     cur_page = NULL;
  98.     for (pptr = pages; pptr < &pages[NUM_PHYS_PAGES]; ++pptr) {
  99.         pptr->page_loc = 'M';
  100.         pptr->is_mod = FALSE;
  101.         pptr->next = pptr + 1;
  102.         pptr->prev = pptr - 1;
  103.         }
  104.     first_phys_page = pages;
  105.     first_phys_page->prev = NULL;
  106.     last_phys_page = pptr - 1;
  107.     last_phys_page->next = NULL;
  108.  
  109.     getmark = BMarkCreate();
  110.  
  111.     for (cnt = 0; cnt < MAXMARK; cnt++) marks[cnt].pptr = NULL;
  112.     for (cnt = 0; cnt < MAXSMARK; cnt++) screenmarks[cnt].pptr = NULL;
  113.     for (cnt = 0; cnt < NUMBUFFERS; cnt++) buffers[cnt].num_pages = 0;
  114.  
  115.     for (cnt = 0; cnt < SWAPMAPSIZE; cnt++) swap_map[cnt] = 0;
  116.     num_swap = ((long)swap_size * 1024) / PAGESIZE;
  117.  
  118. #if defined(MSDOS)
  119.     swap_base = BlockAlloc(swap_size * (1024 / 16));
  120.     return(swap_base != 0);
  121. #endif
  122. #if defined(UNIX)
  123.     swap_base = (char *)malloc(swap_size * 1024);
  124.     return(swap_base != NULL);
  125. #endif
  126.     }
  127.  
  128.  
  129. /* ------------------------------------------------------------ */
  130.  
  131. /* Terminate the buffer abstraction. */
  132.  
  133. void
  134. BFini()
  135.     {
  136. #if defined(MSDOS)
  137.     BlockFree(swap_base);
  138. #endif
  139. #if defined(UNIX)
  140.     free(swap_base);
  141. #endif
  142.     }
  143.  
  144.  
  145. /* ------------------------------------------------------------ */
  146.  
  147. /* Create a buffer. Returns a pointer to the buffer descriptor or NULL. */
  148.  
  149. struct buffer *
  150. BBufCreate(fname)
  151.     char *fname;
  152.     {
  153.     int cnt;
  154.     struct buffer *bptr;
  155.  
  156.     for (cnt = 0; cnt < NUMBUFFERS && !BIsFree(&buffers[cnt]); cnt++) ;
  157.     if (cnt >= NUMBUFFERS) {
  158.         DError("No free buffers");
  159.         return(NULL);
  160.         }
  161.  
  162.         /* copy parameters from previous buffer */
  163.     buffers[cnt].c = (cbuf == NULL) ? c.d : cbuf->c;
  164.  
  165.     bptr = &buffers[cnt];
  166.     xstrcpy(bptr->fname, fname);
  167.     bptr->num_pages = 1;
  168.     bptr->is_mod = FALSE;
  169.     bptr->point_offset = 0;
  170.  
  171.     if ((bptr->point_page = B_PageAllocate(bptr, NULL, NULL)) == NULL)
  172.         return(NULL);
  173.  
  174.     BBufGoto(bptr);
  175.     bptr->mptr = BMarkCreate();
  176.     mark = bptr->mptr;
  177.     return(bptr);
  178.     }
  179.  
  180.  
  181. /* ------------------------------------------------------------ */
  182.  
  183. /* Delete the buffer and all associated pages.  If no non-system
  184. buffers are left, re-create scratch. */
  185.  
  186. void
  187. BBufDelete(delptr)
  188.     struct buffer *delptr;
  189.     {
  190.     struct buffer *bptr;
  191.  
  192.     if (delptr == cbuf || delptr == NULL) {
  193.         DError("Can't delete the current buffer");
  194.         return;
  195.         }
  196.     if (strequ(delptr->fname, SYS_KILL)) {
  197.         DError("Can't delete the kill buffer");
  198.         return;
  199.         }
  200.     while (delptr->first != NULL) B_PageFree(delptr, delptr->first);
  201.     delptr->num_pages = 0;
  202.  
  203.     for (bptr = buffers; bptr < &buffers[NUMBUFFERS]; bptr++) {
  204.         if (!BIsFree(bptr) && (!IS_SYS(bptr->fname) ||
  205.              strequ(bptr->fname, SYS_SCRATCH)))
  206.             return;
  207.         }
  208.     BBufCreate(SYS_SCRATCH);
  209.     }
  210.  
  211.  
  212. /* ------------------------------------------------------------ */
  213.  
  214. /* Locate a buffer with a buffer name of exactly NAME (preferred) or
  215. starting with NAME (backup). */
  216.  
  217. struct buffer *
  218. BBufFind(name)
  219.     char *name;
  220.     {
  221.     struct buffer *bptr;
  222.  
  223.     for (bptr = cbuf + 1; 1; bptr++) {
  224.         if (bptr >= &buffers[NUMBUFFERS]) bptr = buffers;
  225.         if (!BIsFree(bptr) && strequ(name, bptr->fname)) return(bptr);
  226.         if (bptr == cbuf) break;
  227.         }
  228.  
  229.     for (bptr = cbuf + 1; 1; bptr++) {
  230.         if (bptr >= &buffers[NUMBUFFERS]) bptr = buffers;
  231.         if (!BIsFree(bptr) && strnequ(name, bptr->fname, strlen(name)))
  232.             return(bptr);
  233.         if (bptr == cbuf) break;
  234.         }
  235.     return(NULL);
  236.     }
  237.  
  238.  
  239. /* ------------------------------------------------------------ */
  240.  
  241. /* Switch to the specified buffer. */
  242.  
  243. void
  244. BBufGoto(bptr)
  245.     struct buffer *bptr;
  246.     {
  247.     if (bptr == NULL || bptr->num_pages == 0) {
  248.         DError("Not a buffer");
  249.         return;
  250.         }
  251.     if (cbuf != NULL) {
  252.         cbuf->point_page = cur_page;
  253.         cbuf->point_offset = cur_pt_offset;
  254.         }
  255.     B_PageToCurrent(bptr->point_page);
  256.     B_MovePointTo(bptr->point_offset);
  257.     cbuf = bptr;
  258.     cur_col = -1;
  259.     mark = cbuf->mptr;
  260.     }
  261.  
  262.  
  263. /* ------------------------------------------------------------ */
  264.  
  265. /* Clear the current buffer's modified flag. */
  266.  
  267. void
  268. BBufUnmod()
  269.     {
  270.     cbuf->is_mod = FALSE;
  271.     }
  272.  
  273.  
  274. /* ------------------------------------------------------------ */
  275.  
  276. /* Change the current character to TO. */
  277.  
  278. void
  279. BCharChange(to)
  280.     char to;
  281.     {
  282.     if (!BIsEnd()) {
  283.         *cur_cptr = to;
  284.         cbuf->is_mod = TRUE;
  285.         cur_is_mod = TRUE;
  286.         B_SetScreenMarks(FALSE);
  287.         BMoveBy(1);
  288.         }
  289.     else    BInsChar(to);
  290.     }
  291.  
  292.  
  293. /* ------------------------------------------------------------ */
  294.  
  295. /* Delete AMOUNT characters.  If AMOUNT is negative, delete backwards. */
  296.  
  297. void
  298. BCharDelete(amount)
  299.     int amount;
  300.     {
  301.     int num = amount;
  302.     int tmp;
  303.     struct mark *mptr;
  304.     struct virt_page *vpage;
  305.  
  306.     if (amount == 0) return;
  307.     B_GetGap();
  308.  
  309.     if (cur_pt_offset + amount > cur_page_len)
  310.         num = cur_page_len - cur_pt_offset;
  311.     if (num < 0) num = 0;
  312.  
  313.     cur_gap_end += num;
  314.     cur_page_len -= num;
  315.     if (cur_page == cbuf->last) amount = num;
  316.  
  317.     amount -= num;
  318.     cbuf->is_mod = TRUE;
  319.     cur_is_mod = TRUE;
  320.     if (cur_page_len == 0 &&
  321.          (cur_page->next != NULL || cur_page->prev != NULL)) {
  322.         vpage = cur_page->next;
  323.         tmp = 0;
  324.         if (vpage == NULL) {
  325.             vpage = cur_page->prev;
  326.             tmp = vpage->page_len;
  327.             }
  328.         B_MarkUpdateNP(vpage, tmp);
  329.         B_PageFree(cbuf, cur_page);
  330.         cur_page = NULL;
  331.         }
  332.     else    {
  333.         vpage = cur_page;
  334.         tmp = cur_pt_offset;
  335.         if (tmp >= cur_page_len && cur_page->next) {
  336.             vpage = cur_page->next;
  337.             tmp = 0;
  338.             }
  339.         B_MarkUpdate(vpage, num, tmp);
  340.         }
  341.     B_PageToCurrent(vpage);
  342.     B_MovePointTo(tmp);
  343.     if (amount != 0)
  344.         BCharDelete(amount);
  345.     else    B_SetScreenMarks(TRUE);
  346.     }
  347.  
  348.  
  349. /* ------------------------------------------------------------ */
  350.  
  351. /* Load the buffer with the current file. */
  352.  
  353. FLAG
  354. BFileRead()
  355.     {
  356.     int fd;
  357.     int len;
  358.     struct mark *mptr;
  359. #if defined(UNIX)
  360.     struct stat statbuf;
  361. #endif
  362. #if defined(MSDOS)
  363.     FLAG cr_found = FALSE;
  364. #endif
  365.     FLAG ok = TRUE;
  366.  
  367.     B_PageToCurrent(cbuf->first);
  368.     while (cur_page->next != NUL) B_PageFree(cbuf, cur_page->next);
  369.  
  370.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  371.         if (mptr->pptr && mptr->bptr == cbuf) {
  372.             mptr->pptr = cur_page;
  373.             mptr->mark_offset = 0;
  374.             mptr->is_mod = TRUE;
  375.             }
  376.         }
  377.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  378.         if (mptr->pptr != NULL && mptr->bptr == cbuf) {
  379.             mptr->pptr = cur_page;
  380.             mptr->mark_offset = 0;
  381.             mptr->is_mod = TRUE;
  382.             }
  383.         }
  384.  
  385. #if defined(MSDOS)
  386. #define O_RDONLY    0    /* dummy */
  387. #endif
  388.     if ((fd = open(cbuf->fname, O_RDONLY, 0)) < 0) {
  389.         B_MovePointTo(0);
  390.         cur_gap_start = cur_page_start;
  391.         cur_gap_end = cur_page_start + PAGESIZE;
  392.         cur_page_len = 0;
  393.         cur_is_mod = FALSE;
  394.         cbuf->is_mod = FALSE;
  395.         cur_col = 0;
  396. #if defined(UNIX)
  397.         cbuf->file_time = 0;
  398. #endif
  399.         return(FALSE);
  400.         }
  401.  
  402.     while ((len = read(fd, cur_page_start, PAGESIZE)) > 0) {
  403.         cur_gap_start = cur_page_start + len;
  404.         cur_gap_end = cur_page_start + PAGESIZE;
  405.         cur_page_len = len;
  406.         B_MovePointTo(0);
  407.         cur_is_mod = TRUE;
  408. #if defined(MSDOS)
  409.         if (!isuarg && cr_found && *cur_cptr == LF) {
  410.             *cur_page_start = NL;
  411.             --(cur_page->prev->page_len);
  412.             --(cur_page->prev->gap_start);
  413.             }
  414.         cr_found = FALSE;
  415.         while (cur_pt_offset < cur_page_len) {
  416.             if (!isuarg && *cur_cptr == ZCZ) break;
  417.             if (!isuarg && *cur_cptr == CR) {
  418.                 B_MovePointTo(cur_pt_offset + 1);
  419.                 B_GetGap();
  420.                 if (cur_pt_offset >= cur_page_len)
  421.                     cr_found = TRUE;
  422.                 else if (*cur_cptr == LF) {
  423.                     --cur_gap_start;
  424.                     --cur_page_len;
  425.                     *cur_gap_end = NL;
  426.                     }
  427.                 B_MovePointTo(cur_pt_offset - 1);
  428.                 }
  429.             B_MovePointTo(cur_pt_offset + 1);
  430.             }
  431.         if ((!isuarg && *cur_cptr == ZCZ) || len < PAGESIZE) break;
  432. #else
  433.         B_MovePointTo(cur_page_len);
  434.         if (len < PAGESIZE) break;
  435. #endif
  436.         if (B_PageAllocate(cbuf, cur_page, NULL) == NULL) {
  437.             ok = FALSE;
  438.             break;
  439.             }
  440.         B_PageToCurrent(cur_page->next);
  441.         B_MovePointTo(0);
  442.         }
  443. #if defined(UNIX)
  444.     fstat(fd, &statbuf);
  445.     cbuf->file_time = statbuf.st_mtime;
  446. #endif
  447.     close(fd);
  448.     if (cur_pt_offset == 0 && cur_page != cbuf->first) {
  449.         B_PageFree(cbuf, cur_page);
  450.         cur_page = NULL;
  451.         }
  452.     else    {
  453.         B_GetGap();
  454.         cur_gap_end = cur_page_start + PAGESIZE;
  455.         cur_page_len = cur_pt_offset;
  456.         }
  457.     B_PageToCurrent(cbuf->first);
  458.     B_MovePointTo(0);
  459.     cur_col = 0;
  460.     cbuf->is_mod = FALSE;
  461.     if (c.g.wrap_allowed) B_FileReadCheck();
  462.     return(ok);
  463.     }
  464.  
  465.  
  466. /* ------------------------------------------------------------ */
  467.  
  468. /* Write the buffer to its file. */
  469.  
  470. FLAG
  471. BFileWrite()
  472.     {
  473.     struct virt_page *vpage;
  474.     struct phys_page *ppage;
  475.     int fd;
  476.     int len;
  477.     FLAG was_err;
  478.     char *cptr;
  479.     char *buf;
  480. #if defined(MSDOS)
  481.     char chr;
  482.  
  483.     if ((fd = creat(cbuf->fname)) < 0) return(FALSE);
  484. #endif
  485. #if defined(UNIX)
  486.     struct stat statbuf;
  487.  
  488.     if (stat(cbuf->fname, &statbuf) >= 0) {
  489.         if ((cbuf->file_time != 0 &&
  490.              (cbuf->file_time != statbuf.st_mtime)) &&
  491.              !KAsk("Overwrite changed/existing file?"))
  492.             return(FALSE);
  493.         }
  494.     if ((fd = open(cbuf->fname, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
  495.         return(FALSE);
  496. #endif
  497.  
  498.     ppage = B_PageFindFree();
  499.     ppage->page_loc = 'L';
  500.     buf = ppage->page_data;
  501.     BMarkToPoint(cwin->point);
  502.     cptr = buf;
  503.     for (vpage = cbuf->first, was_err = FALSE;
  504.          vpage != NULL && !was_err; ) {
  505.         B_PageToCurrent(vpage);
  506.         B_MovePointTo(0);
  507.         vpage = cur_page->next;
  508.         while (cur_pt_offset < cur_page_len) {
  509. #if defined(MSDOS)
  510.             chr = *cur_cptr;
  511.             if (!isuarg && chr == NL) {
  512.                 *cptr++ = CR;
  513.                 if (cptr >= &buf[PAGESIZE]) {
  514.                     was_err = write(fd, buf, PAGESIZE)
  515.                         != PAGESIZE;
  516.                     if (was_err) break;
  517.                     cptr = buf;
  518.                     }
  519.                 chr = LF;
  520.                 }
  521.             *cptr++ = chr;
  522. #else
  523.             *cptr++ = *cur_cptr;
  524. #endif
  525.             if (cptr >= &buf[PAGESIZE]) {
  526.                 was_err = write(fd, buf, PAGESIZE) != PAGESIZE;
  527.                 if (was_err) break;
  528.                 cptr = buf;
  529.                 }
  530.             B_MovePointTo(cur_pt_offset + 1);
  531.             }
  532.         }
  533.     len = cptr - buf;
  534.     if (was_err || len != write(fd, buf, len))
  535.         DError("Error writing file");
  536.     else    cbuf->is_mod = FALSE;
  537.     ppage->page_loc = 'M';
  538.     ppage->is_mod = FALSE;
  539. #if defined(UNIX)
  540.     fstat(fd,&statbuf);
  541.     cbuf->file_time = statbuf.st_mtime;
  542. #endif
  543.     close(fd);
  544.     BPointToMark(cwin->point);
  545.     return(TRUE);
  546.     }
  547.  
  548.  
  549. /* ------------------------------------------------------------ */
  550.  
  551. /* Write out one modified page. */
  552.  
  553. void
  554. BFlush()
  555.     {
  556.     struct phys_page *ppage;
  557.  
  558.     for (ppage = last_phys_page; ppage->prev != NULL &&
  559.         (ppage->page_loc != 'S' || !ppage->is_mod);
  560.         ppage = ppage->prev) ;
  561.     if (ppage->prev == NULL) return;
  562.     if (ppage->pptr->page_len != 0) {
  563. #if defined(MSDOS)
  564.         char huge *tmp = (char huge *)((long)swap_base << 16);
  565.         BlockPut(tmp + (long)ppage->page_num * PAGESIZE,
  566.             ppage->page_data, PAGESIZE);
  567. #endif
  568. #if defined(UNIX)
  569.         memmove(swap_base + ppage->page_num * PAGESIZE,
  570.             ppage->page_data, PAGESIZE);
  571. #endif
  572.         }
  573.     ppage->is_mod = FALSE;
  574.     }
  575.  
  576.  
  577. /* ------------------------------------------------------------ */
  578.  
  579. /* Return the current character. */
  580.  
  581. char
  582. BGetChar()
  583.     {
  584.     return(*cur_cptr);
  585.     }
  586.  
  587.  
  588. /* ------------------------------------------------------------ */
  589.  
  590. /* Return the current character and move the point by 1 char.  Same as
  591. c = BGetChar(); BMoveBy(1);, but optimized for speed. */
  592.  
  593. char
  594. BGetCharAdv()
  595.     {
  596.     int num;
  597.     char chr = *cur_cptr;
  598.  
  599.     if (cur_pt_offset >= cur_page_len) return(chr);
  600.     if (chr == NL || chr == SNL)
  601.         cur_col = 0;
  602.     else if (cur_col >= 0)
  603.         cur_col += TGetWidth(chr, cur_col);
  604.     if (++cur_pt_offset < cur_page_len) {
  605.         if (++cur_cptr == cur_gap_start) cur_cptr = cur_gap_end;
  606.         return(chr);
  607.         }
  608.     --cur_pt_offset;
  609.  
  610.     num = cur_pt_offset + 1;
  611.     if (num >= 0 && num < cur_page_len) {
  612.         B_MovePointTo(num);
  613.         return(chr);
  614.         }
  615.     if (num >= cur_page_len && cbuf->last == cur_page) {
  616.         B_MovePointTo(cur_page_len);
  617.         return(chr);
  618.         }
  619.     if (num < 0) {
  620.         if (cur_page == cbuf->first) {
  621.             B_MovePointTo(0);
  622.             return(chr);
  623.             }
  624.         B_PageToCurrent(cur_page->prev);
  625.         B_MovePointTo(cur_page_len);
  626.         }
  627.     else    {
  628.         num -= cur_page_len;    /* must use this cur_page_len */
  629.         B_PageToCurrent(cur_page->next);
  630.         B_MovePointTo(0);
  631.         }
  632.     if (num != 0) BMoveBy(num);
  633.     return(chr);
  634.     }
  635.  
  636.  
  637. /* ------------------------------------------------------------ */
  638.  
  639. /* Return the current column. */
  640.  
  641. int
  642. BGetCol()
  643.     {
  644.  
  645.     if (cur_col >= 0) return(cur_col);
  646.     BMarkToPoint(getmark);
  647.     if (BSearchB(NL, SNL)) BMoveBy(1);
  648.     cur_col = 0;
  649.     while (BIsBeforeMark(getmark)) BMoveBy(1);
  650.     return(cur_col);
  651.     }
  652.  
  653.  
  654. /* ------------------------------------------------------------ */
  655.  
  656. /* Returns the buffer's length. */
  657.  
  658. long
  659. BGetLength(bptr)
  660.     struct buffer *bptr;
  661.     {
  662.     long len;
  663.     struct virt_page *vpage;
  664.  
  665.     len = 0;
  666.     for (vpage = bptr->first; vpage != NULL; vpage = vpage->next) {
  667.         if (vpage == cur_page)
  668.             len += cur_page_len;
  669.         else    len += vpage->page_len;
  670.         }
  671.     return(len);
  672.     }
  673.  
  674.  
  675. /* ------------------------------------------------------------ */
  676.  
  677. /* Return the current point location. */
  678.  
  679. long
  680. BGetLocation()
  681.     {
  682.     long len;
  683.     struct virt_page *vpage;
  684.  
  685.     len = 0;
  686.     for (vpage = cbuf->first; vpage != cur_page; vpage = vpage->next)
  687.         len += vpage->page_len;
  688.     return(len + cur_pt_offset);
  689.     }
  690.  
  691.  
  692. /* ------------------------------------------------------------ */
  693.  
  694. /* Insert the specified character into the buffer. Return True on
  695. success or False on buffer full. */
  696.  
  697. FLAG
  698. BInsChar(chr)
  699.     char chr;
  700.     {
  701.     FLAG ok;
  702.  
  703.     ok = B_InsChar(chr);
  704.     B_SetScreenMarks(FALSE);
  705.     return(ok);
  706.     }
  707.  
  708.  
  709. /* ------------------------------------------------------------ */
  710.  
  711. /* Insert AMT spaces. */
  712.  
  713. void
  714. BInsSpaces(amt)
  715.     int amt;
  716.     {
  717.     while (amt-- > 0) B_InsChar(SP);
  718.     B_SetScreenMarks(FALSE);
  719.     }
  720.  
  721.  
  722. /* ------------------------------------------------------------ */
  723.  
  724. /* Insert the string into the buffer. Return True on success or False
  725. on buffer full. */
  726.  
  727. FLAG
  728. BInsStr(str)
  729.     char *str;
  730.     {
  731.     FLAG ok = TRUE;
  732.  
  733.     while (*str != NUL) {
  734.         if (!B_InsChar(*str++)) {
  735.             ok = FALSE;
  736.             break;
  737.             }
  738.         }
  739.     B_SetScreenMarks(FALSE);
  740.     return(ok);
  741.     }
  742.  
  743.  
  744. /* ------------------------------------------------------------ */
  745.  
  746. /* Put in the right number of tabs and spaces */
  747.  
  748. void
  749. BInsTabSpaces(amt)
  750.     int amt;
  751.     {
  752.     for ( ; amt >= cbuf->c.tab_spacing; amt -= cbuf->c.tab_spacing) {
  753.         B_InsChar(TAB);
  754.         }
  755.     BInsSpaces(amt);
  756.     }
  757.  
  758.  
  759. /* ------------------------------------------------------------ */
  760.  
  761. /* Put the point in a special, repeatable invalid state off the end of
  762. the buffer. */
  763.  
  764. void
  765. BInvalid()
  766.     {
  767.     B_PageToCurrent(cbuf->last);
  768.     B_MovePointTo(cur_page_len + 1);
  769.     cur_col = -1;
  770.     }
  771.  
  772.  
  773. /* ------------------------------------------------------------ */
  774.  
  775. /* Is the point after the mark? */
  776.  
  777. FLAG
  778. BIsAfterMark(mptr)
  779.     struct mark *mptr;
  780.     {
  781.     struct virt_page *vpage;
  782.  
  783.     if (mptr->pptr == NULL || mptr->bptr != cbuf) {
  784.         DError("Bad mark");
  785.         return(FALSE);
  786.         }
  787.     if (mptr->pptr == cur_page) return(cur_pt_offset > mptr->mark_offset);
  788.     for (vpage = cur_page; vpage && vpage != mptr->pptr;
  789.         vpage = vpage->prev);
  790.     return(vpage != NULL);
  791.     }
  792.  
  793.  
  794. /* ------------------------------------------------------------ */
  795.  
  796. /* Is the point at the mark? */
  797.  
  798. FLAG
  799. BIsAtMark(mptr)
  800.     struct mark *mptr;
  801.     {
  802.     return(mptr->pptr == cur_page && mptr->mark_offset == cur_pt_offset);
  803.     }
  804.  
  805.  
  806. /* ------------------------------------------------------------ */
  807.  
  808. /* Is the point before the mark? */
  809.  
  810. FLAG
  811. BIsBeforeMark(mptr)
  812.     struct mark *mptr;
  813.     {
  814.     struct virt_page *vpage;
  815.  
  816.     if (mptr->pptr == NULL || mptr->bptr != cbuf) {
  817.         DError("Bad mark");
  818.         return(FALSE);
  819.         }
  820.     if (mptr->pptr == cur_page) return(cur_pt_offset < mptr->mark_offset);
  821.     for (vpage = cur_page; vpage != NULL && vpage != mptr->pptr;
  822.         vpage = vpage->next);
  823.     return(vpage != NULL);
  824.     }
  825.  
  826.  
  827. /* ------------------------------------------------------------ */
  828.  
  829. /* Is the point at the end of the buffer? */
  830.  
  831. FLAG
  832. BIsEnd()
  833.     {
  834.     return(cur_pt_offset >= cur_page_len && cur_page == cbuf->last);
  835.     }
  836.  
  837.  
  838. /* ------------------------------------------------------------ */
  839.  
  840. /* Return True if the buffer is free, or False if it is in use. */
  841.  
  842. FLAG
  843. BIsFree(bptr)
  844.     struct buffer *bptr;
  845.     {
  846.     return(bptr->num_pages == 0);
  847.     }
  848.  
  849.  
  850. /* ------------------------------------------------------------ */
  851.  
  852. /* Has the buffer been modified? */
  853.  
  854. FLAG
  855. BIsMod(bptr)
  856.     struct buffer *bptr;
  857.     {
  858.     return(bptr->is_mod);
  859.     }
  860.  
  861.  
  862. /* ------------------------------------------------------------ */
  863.  
  864. /* Is the point at the beginning of the buffer? */
  865.  
  866. FLAG
  867. BIsStart()
  868.     {
  869.     return(cur_pt_offset == 0 && cur_page == cbuf->first);
  870.     }
  871.  
  872.  
  873. /* ------------------------------------------------------------ */
  874.  
  875. /* Put the cursor in specific column, rounding. */
  876.  
  877. void
  878. BMakeColB(col)
  879.     int col;
  880.     {
  881.     int old_col;
  882.  
  883.     if (BSearchB(NL, SNL)) BMoveBy(1);
  884.     cur_col = 0;
  885.     while (cur_col < col && *cur_cptr != NL && *cur_cptr != SNL &&
  886.          !BIsEnd()) {
  887.         old_col = cur_col;
  888.         BMoveBy(1);
  889.         }
  890.     if (cur_col != 0 && cur_col - col > col - old_col) BMoveBy(-1);
  891.     }
  892.  
  893.  
  894. /* ------------------------------------------------------------ */
  895.  
  896. /* Put cursor in specific column, no rounding. */
  897.  
  898. void
  899. BMakeColF(col)
  900.     int col;
  901.     {
  902.     if (BSearchB(NL, SNL)) BMoveBy(1);
  903.     cur_col = 0;
  904.     while (cur_col < col && *cur_cptr != NL && *cur_cptr != SNL &&
  905.          !BIsEnd()) {
  906.         BMoveBy(1);
  907.         }
  908.     }
  909.  
  910.  
  911. /* ------------------------------------------------------------ */
  912.  
  913. /* Return the mark's buffer. */
  914.  
  915. struct buffer *
  916. BMarkBuf(mptr)
  917.     struct mark *mptr;
  918.     {
  919.     return(mptr->bptr);
  920.     }
  921.  
  922.  
  923. /* ------------------------------------------------------------ */
  924.  
  925. /* Create a mark at the point. */
  926.  
  927. struct mark *
  928. BMarkCreate()
  929.     {
  930.     struct mark *mptr;
  931.  
  932.     for (mptr = marks; mptr < &marks[MAXMARK] && mptr->pptr != NULL;
  933.         mptr++) ;
  934.     if (mptr >= &marks[MAXMARK - 1]) {
  935.         DError("Out of marks");
  936.         mptr = &marks[MAXMARK - 1];
  937.         }
  938.     mptr->bptr = cbuf;
  939.     mptr->pptr = cur_page;
  940.     mptr->mark_offset = cur_pt_offset;
  941.     return(mptr);
  942.     }
  943.  
  944.  
  945. /* ------------------------------------------------------------ */
  946.  
  947. /* Free the supplied mark. */
  948.  
  949. void
  950. BMarkDelete(mptr)
  951.     struct mark *mptr;
  952.     {
  953.     mptr->pptr = NULL;
  954.     }
  955.  
  956.  
  957. /* ------------------------------------------------------------ */
  958.  
  959. /* Test and clear the modified flag on the specified screen mark. */
  960.  
  961. FLAG
  962. BMarkIsMod(mptr)
  963.     struct mark *mptr;
  964.     {
  965.     FLAG is_mod;
  966.  
  967.     is_mod = mptr->is_mod;
  968.     mptr->is_mod = FALSE;
  969.     return(mptr->bptr != cbuf || is_mod);
  970.     }
  971.  
  972.  
  973. /* ------------------------------------------------------------ */
  974.  
  975. /* Set the modified flag on the specified screen mark. */
  976.  
  977. void
  978. BMarkSetMod(mptr)
  979.     struct mark *mptr;
  980.     {
  981.     mptr->is_mod = TRUE;
  982.     }
  983.  
  984.  
  985. /* ------------------------------------------------------------ */
  986.  
  987. /* Return the mark for the specifed row. */
  988.  
  989. struct mark *
  990. BMarkScreen(row)
  991.     int row;
  992.     {
  993.     return(&screenmarks[row]);
  994.     }
  995.  
  996.  
  997. /* ------------------------------------------------------------ */
  998.  
  999. /* Swap the point and the mark. */
  1000.  
  1001. void
  1002. BMarkSwap(mptr)
  1003.     struct mark *mptr;
  1004.     {
  1005.     struct mark tmp;
  1006.  
  1007.     tmp = *mptr;
  1008.     BMarkToPoint(mptr);
  1009.     BPointToMark(&tmp);
  1010.     }
  1011.  
  1012.  
  1013. /* ------------------------------------------------------------ */
  1014.  
  1015. /* Put the mark where the point is. */
  1016.  
  1017. void
  1018. BMarkToPoint(mptr)
  1019.     struct mark *mptr;
  1020.     {
  1021.     mptr->bptr = cbuf;
  1022.     mptr->pptr = cur_page;
  1023.     mptr->mark_offset = cur_pt_offset;
  1024.     }
  1025.  
  1026.  
  1027. /* ------------------------------------------------------------ */
  1028.  
  1029. /* Move the point relative to its current position by AMT characters.
  1030. */
  1031.  
  1032. void
  1033. BMoveBy(amt)
  1034.     int amt;
  1035.     {
  1036.     int num;
  1037.  
  1038.     if (amt == 1) {
  1039.         if (cur_pt_offset >= cur_page_len) return;
  1040.         if (*cur_cptr == NL || *cur_cptr == SNL)
  1041.             cur_col = 0;
  1042.         else if (cur_col >= 0)
  1043.             cur_col += TGetWidth(*cur_cptr, cur_col);
  1044.         if (++cur_pt_offset < cur_page_len) {
  1045.             if (++cur_cptr == cur_gap_start)
  1046.                 cur_cptr = cur_gap_end;
  1047.             return;
  1048.             }
  1049.         --cur_pt_offset;
  1050.         }
  1051.     else    cur_col = -1;
  1052.  
  1053.     num = cur_pt_offset + amt;
  1054.     if (num >= 0 && num < cur_page_len) {
  1055.         B_MovePointTo(num);
  1056.         return;
  1057.         }
  1058.     if (num >= cur_page_len && cbuf->last == cur_page) {
  1059.         B_MovePointTo(cur_page_len);
  1060.         return;
  1061.         }
  1062.     if (num < 0) {
  1063.         if (cur_page == cbuf->first) {
  1064.             B_MovePointTo(0);
  1065.             return;
  1066.             }
  1067.         B_PageToCurrent(cur_page->prev);
  1068.         B_MovePointTo(cur_page_len);
  1069.         }
  1070.     else    {
  1071.         num -= cur_page_len;    /* must use this cur_page_len */
  1072.         B_PageToCurrent(cur_page->next);
  1073.         B_MovePointTo(0);
  1074.         }
  1075.  
  1076.     if (num != 0) BMoveBy(num);
  1077.     }
  1078.  
  1079.  
  1080. /* ------------------------------------------------------------ */
  1081.  
  1082. /* Set the point to the end of the buffer. */
  1083.  
  1084. void
  1085. BMoveToEnd()
  1086.     {
  1087.     B_PageToCurrent(cbuf->last);
  1088.     B_MovePointTo(cur_page_len);
  1089.     cur_col = -1;
  1090.     }
  1091.  
  1092.  
  1093. /* ------------------------------------------------------------ */
  1094.  
  1095. /* Set the point to the start of the buffer. */
  1096.  
  1097. void
  1098. BMoveToStart()
  1099.     {
  1100.     B_PageToCurrent(cbuf->first);
  1101.     B_MovePointTo(0);
  1102.     cur_col = 0;
  1103.     }
  1104.  
  1105.  
  1106. /* ------------------------------------------------------------ */
  1107.  
  1108. /* Move the point to the specified mark. */
  1109.  
  1110. void
  1111. BPointToMark(mptr)
  1112.     struct mark *mptr;
  1113.     {
  1114.     if (mptr->pptr == NULL) {
  1115.         DError("Not a mark");
  1116.         return;
  1117.         }
  1118.     if (mptr->bptr != cbuf) BBufGoto(mptr->bptr);
  1119.     B_PageToCurrent(mptr->pptr);
  1120.     B_MovePointTo(mptr->mark_offset);
  1121.     cur_col = -1;
  1122.     }
  1123.  
  1124.  
  1125. /* ------------------------------------------------------------ */
  1126.  
  1127. /* Restore the current column. */
  1128.  
  1129. void
  1130. BPopState()
  1131.     {
  1132.     cur_col = savecol;
  1133.     }
  1134.  
  1135.  
  1136. /* ------------------------------------------------------------ */
  1137.  
  1138. /* Save the current column. */
  1139.  
  1140. void
  1141. BPushState()
  1142.     {
  1143.     savecol = cur_col;
  1144.     }
  1145.  
  1146.  
  1147. /* ------------------------------------------------------------ */
  1148.  
  1149. /* Copy the region from the current point to mark MPTR to the buffer
  1150. specified by BPTR. */
  1151.  
  1152. void
  1153. BRegCopy(mptr, bptr)
  1154.     struct mark *mptr;
  1155.     struct buffer *bptr;
  1156.     {
  1157.     struct buffer *save_buf = cbuf;
  1158.     struct mark *mptr2;
  1159.     struct mark *mptr3;
  1160.     FLAG isafter;
  1161.     int from;
  1162.     int to;
  1163.     char *save_point;
  1164.  
  1165.     if (bptr == cbuf) {
  1166.         DError("Must copy to a different buffer");
  1167.         return;
  1168.         }
  1169.     if (isafter = BIsAfterMark(mptr)) BMarkSwap(mptr);
  1170.     mptr2 = BMarkCreate();
  1171.     while (BIsBeforeMark(mptr)) {
  1172.         if (cur_page == mptr->pptr)
  1173.             from = mptr->mark_offset - cur_pt_offset;
  1174.         else    from = cur_page_len - cur_pt_offset;
  1175.         B_GetGap();
  1176.         cur_is_mod = TRUE;
  1177.         save_point = cur_gap_end;
  1178.  
  1179.         BBufGoto(bptr);
  1180.         to = PAGESIZE - cur_page_len;
  1181.         if (to == 0)
  1182.             if (B_PageSplit(cur_pt_offset +
  1183.                  ((cur_pt_offset < PAGESIZE / 2) ? 1 : -1)))
  1184.                 to = PAGESIZE - cur_page_len;
  1185.             else     {
  1186.                 BBufGoto(save_buf);
  1187.                 break;
  1188.                 }
  1189.         B_GetGap();
  1190.         if (from < to) to = from;
  1191.         memmove(cur_gap_start, save_point, to);
  1192.         cur_page_len += to;
  1193.         cur_gap_start += to;
  1194.         for (mptr3 = marks; mptr3 < &marks[MAXMARK]; ++mptr3) {
  1195.             if (mptr3->pptr == cur_page &&
  1196.                  mptr3->mark_offset > cur_pt_offset) {
  1197.                 mptr3->mark_offset += to;
  1198.                 }
  1199.             }
  1200.         for (mptr3 = screenmarks; mptr3 < &screenmarks[MAXSMARK];
  1201.              ++mptr3) {
  1202.             if (mptr3->pptr == cur_page &&
  1203.                  mptr3->mark_offset > cur_pt_offset) {
  1204.                 mptr3->mark_offset += to;
  1205.                 }
  1206.             }
  1207.         B_MovePointTo(cur_pt_offset + to);
  1208.         B_SetScreenMarks(FALSE);
  1209.         cur_is_mod = TRUE;
  1210.         cbuf->is_mod = TRUE;
  1211.         BBufGoto(save_buf);
  1212.         BMoveBy(to);
  1213.         }
  1214.     BPointToMark(mptr2);
  1215.     BMarkDelete(mptr2);
  1216.     if (isafter) BMarkSwap(mptr);
  1217.     }
  1218.  
  1219.  
  1220. /* ------------------------------------------------------------ */
  1221.  
  1222. /* delete from the point to the mark */
  1223.  
  1224. void
  1225. BRegDelete(mptr)
  1226.     struct mark *mptr;
  1227.     {
  1228.     if (BIsAfterMark(mptr)) BMarkSwap(mptr);
  1229.     if (!BIsBeforeMark(mptr)) return;
  1230.  
  1231.     if (cur_page == mptr->pptr)
  1232.         BCharDelete(mptr->mark_offset - cur_pt_offset);
  1233.     else    {
  1234.         BCharDelete(cur_page_len - cur_pt_offset);
  1235.         BRegDelete(mptr);
  1236.         }
  1237.     }
  1238.  
  1239.  
  1240. /* ------------------------------------------------------------ */
  1241.  
  1242. /* Search backwards for both C1 and C2. */
  1243.  
  1244. FLAG
  1245. BSearchB(c1, c2)
  1246.     char c1;
  1247.     char c2;
  1248.     {
  1249.     char *cptr;
  1250.  
  1251.     do    {
  1252.         if (BIsStart()) return(FALSE);
  1253.         if (BIsEnd() || cur_cptr == cur_gap_end ||
  1254.              cur_cptr == cur_page_start)
  1255.             BMoveBy(-1);
  1256.         else    {
  1257.             cptr = (cur_cptr >= cur_gap_end) ? cur_gap_end :
  1258.                 cur_page_start;
  1259.             BMoveBy(max(
  1260.                 B_IndexB(cur_cptr - 1, cur_cptr - cptr, c1),
  1261.                 B_IndexB(cur_cptr - 1, cur_cptr - cptr, c2))
  1262.                     - 1);
  1263.             }
  1264.         } while (*cur_cptr != c1 && *cur_cptr != c2);
  1265.     return(TRUE);
  1266.     }
  1267.  
  1268.  
  1269. /* ------------------------------------------------------------ */
  1270.  
  1271. /* Search forward for both C1 and C2. */
  1272.  
  1273. FLAG
  1274. BSearchF(c1, c2)
  1275.     char c1;
  1276.     char c2;
  1277.     {
  1278.     while (!BIsEnd() && *cur_cptr != c1 && *cur_cptr != c2) {
  1279.         if (cur_cptr >= cur_gap_start) {
  1280.             B_MovePointTo(cur_pt_offset + min(
  1281. B_IndexF(cur_cptr, (cur_page_start + PAGESIZE) - cur_cptr, c1),
  1282. B_IndexF(cur_cptr, (cur_page_start + PAGESIZE) - cur_cptr, c2)));
  1283.             }
  1284.         else    {
  1285.             B_MovePointTo(cur_pt_offset + min(
  1286. B_IndexF(cur_cptr, cur_gap_start - cur_cptr, c1),
  1287. B_IndexF(cur_cptr, cur_gap_start - cur_cptr, c2)));
  1288.             }
  1289.         if (cur_pt_offset >= cur_page_len && cur_page->next) {
  1290.             B_PageToCurrent(cur_page->next);
  1291.             B_MovePointTo(0);
  1292.             }
  1293.         }
  1294.     cur_col = -1;
  1295.     if (!BIsEnd()) {
  1296.         BMoveBy(1);
  1297.         return(TRUE);
  1298.         }
  1299.     else    return(FALSE);
  1300.     }
  1301.  
  1302.  
  1303. /* ------------------------------------------------------------ */
  1304.  
  1305. /* The buffer has just been read in.  Check it for a ruler line. */
  1306.  
  1307. void
  1308. B_FileReadCheck()
  1309.     {
  1310.     if (IsNL()) BMoveBy(1);
  1311.     for (;;) {
  1312.         if (*cur_cptr == SP || *cur_cptr == TAB) {
  1313.             MovePastF(IsWhite);
  1314.             if (!IsNL()) break;
  1315.             BMoveBy(1);
  1316.             }
  1317.         else if (*cur_cptr == '.' || *cur_cptr == '@') {
  1318.             SearchNLF();
  1319.             }
  1320.         else if (*cur_cptr == ZCK) {
  1321.             B_RulerLine();
  1322.             break;
  1323.             }
  1324.         else break;
  1325.         }
  1326.     BMoveToStart();
  1327.     }
  1328.  
  1329.  
  1330. /* ------------------------------------------------------------ */
  1331.  
  1332. /* Move the gap to the point. */
  1333.  
  1334. void
  1335. B_GetGap()
  1336.     {
  1337.     if (cur_cptr == cur_gap_end) return;
  1338.  
  1339.     if (cur_cptr < cur_gap_start) {
  1340.         cur_gap_end -= cur_gap_start - cur_cptr;
  1341.         memmove(cur_gap_end, cur_cptr, cur_gap_start - cur_cptr);
  1342.         cur_gap_start = cur_cptr;
  1343.         cur_cptr = cur_gap_end;
  1344.         }
  1345.     else    {
  1346.         memmove(cur_gap_start, cur_gap_end, cur_cptr - cur_gap_end);
  1347.         cur_gap_start += cur_cptr - cur_gap_end;
  1348.         cur_gap_end = cur_cptr;
  1349.         }
  1350.     }
  1351.  
  1352.  
  1353. /* ------------------------------------------------------------ */
  1354.  
  1355. /* Return the offset of CHR backwards in BUF, which is LEN characters
  1356. long. */
  1357.  
  1358. int
  1359. B_IndexB(buf, len, chr)
  1360.     char *buf;
  1361.     int len;
  1362.     char chr;
  1363.     {
  1364.     char *cptr;
  1365.  
  1366.     for (cptr = buf; len-- > 0 && *cptr != chr; --cptr) ;
  1367.     return(cptr - buf);
  1368.     }
  1369.  
  1370.  
  1371. /* ------------------------------------------------------------ */
  1372.  
  1373. /* Return the offset of CHR in BUF, which is LEN characters long. */
  1374.  
  1375. int
  1376. B_IndexF(buf, len, chr)
  1377.     char *buf;
  1378.     int len;
  1379.     char chr;
  1380.     {
  1381.     char *cptr;
  1382.  
  1383.     for (cptr = buf; len-- > 0 && *cptr != chr; ++cptr) ;
  1384.     return(cptr - buf);
  1385.     }
  1386.  
  1387.  
  1388. /* ------------------------------------------------------------ */
  1389.  
  1390. /* Insert the specified character into the buffer. */
  1391.  
  1392. FLAG
  1393. B_InsChar(chr)
  1394.     char chr;
  1395.     {
  1396.     struct mark *mptr;
  1397.  
  1398.     if (cur_gap_start == cur_gap_end && !B_PageSplit(PAGESIZE / 2))
  1399.         return(FALSE);
  1400.     B_GetGap();                
  1401.     *cur_gap_start++ = chr;
  1402.     ++cur_page_len;
  1403.     B_MovePointTo(cur_pt_offset + 1);
  1404.  
  1405.     if (chr == NL || chr == SNL)
  1406.         cur_col = 0;
  1407.     else if (cur_col >= 0)
  1408.         cur_col += TGetWidth(chr, cur_col);
  1409.  
  1410.     cbuf->is_mod = TRUE;
  1411.     cur_is_mod = TRUE;
  1412.  
  1413.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1414.         if (mptr->pptr == cur_page &&
  1415.              mptr->mark_offset >= cur_pt_offset) {
  1416.             ++(mptr->mark_offset);
  1417.             }
  1418.         }
  1419.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1420.         if (mptr->pptr == cur_page &&
  1421.              mptr->mark_offset >= cur_pt_offset) {
  1422.             ++(mptr->mark_offset);
  1423.             }
  1424.         }
  1425.     return(TRUE);
  1426.     }
  1427.  
  1428.  
  1429. /* ------------------------------------------------------------ */
  1430.  
  1431. /* Update the marks to a new page using NEW_PAGE, AMT, NEW_OFFSET. */
  1432.  
  1433. void
  1434. B_MarkUpdate(new_page, amt, new_offset)
  1435.     struct virt_page *new_page;
  1436.     int amt;
  1437.     int new_offset;
  1438.     {
  1439.     struct mark *mptr;
  1440.  
  1441.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1442.         if (mptr->pptr == cur_page &&
  1443.              mptr->mark_offset >= cur_pt_offset) {
  1444.             if (mptr->mark_offset >= cur_pt_offset + amt)
  1445.                 mptr->mark_offset -= amt;
  1446.             else    {
  1447.                 mptr->pptr = new_page;
  1448.                 mptr->mark_offset = new_offset;
  1449.                 }
  1450.             }
  1451.         }
  1452.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1453.         if (mptr->pptr == cur_page &&
  1454.              mptr->mark_offset >= cur_pt_offset) {
  1455.             if (mptr->mark_offset >= cur_pt_offset + amt)
  1456.                 mptr->mark_offset -= amt;
  1457.             else    {
  1458.                 mptr->pptr = new_page;
  1459.                 mptr->mark_offset = new_offset;
  1460.                 }
  1461.             }
  1462.         }
  1463.     }
  1464.  
  1465.  
  1466. /* ------------------------------------------------------------ */
  1467.  
  1468. /* Update the marks to a new page using NEW_PAGE, NEW_OFFSET. */
  1469.  
  1470. void
  1471. B_MarkUpdateNP(new_page, new_offset)
  1472.     struct virt_page *new_page;
  1473.     int new_offset;
  1474.     {
  1475.     struct mark *mptr;
  1476.  
  1477.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1478.         if (mptr->pptr == cur_page) {
  1479.             mptr->pptr = new_page;
  1480.             mptr->mark_offset = new_offset;
  1481.             }
  1482.         }
  1483.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1484.         if (mptr->pptr == cur_page) {
  1485.             mptr->pptr = new_page;
  1486.             mptr->mark_offset = new_offset;
  1487.             }
  1488.         }
  1489.     }
  1490.  
  1491.  
  1492. /* ------------------------------------------------------------ */
  1493.  
  1494. /* Move the point AMT chars into the current page. */
  1495.  
  1496. void
  1497. B_MovePointTo(amt)
  1498.     int amt;
  1499.     {
  1500.     cur_pt_offset = amt;
  1501.     cur_cptr = cur_page_start + amt;
  1502.     if (cur_cptr >= cur_gap_start) cur_cptr += cur_gap_end - cur_gap_start;
  1503.     }
  1504.  
  1505.  
  1506. /* ------------------------------------------------------------ */
  1507.  
  1508. /* Allocate a new page. */
  1509.  
  1510. struct virt_page *
  1511. B_PageAllocate(bptr, prev, next)
  1512.     struct buffer *bptr;
  1513.     struct virt_page *prev;
  1514.     struct virt_page *next;
  1515.     {
  1516.     int cnt;
  1517.     struct virt_page *vpage;
  1518.     struct phys_page *ppage;
  1519.  
  1520.     for (cnt = 0; cnt < num_swap && swap_map[cnt]; ++cnt) ;
  1521.     if (cnt >= num_swap) {
  1522.         DError("Out of swap space");
  1523.         return(NULL);
  1524.         }
  1525.     vpage = (struct virt_page *)malloc(sizeof(struct virt_page));
  1526.     if (vpage == NULL) {
  1527.         DError("Out of heap space");
  1528.         return(NULL);
  1529.         }
  1530.  
  1531.     swap_map[cnt] = TRUE;
  1532.  
  1533.     vpage->next = next;
  1534.     vpage->prev = prev;
  1535.     if (next != NULL)
  1536.         next->prev = vpage;
  1537.     else    bptr->last = vpage;
  1538.     if (prev != NULL)
  1539.         prev->next = vpage;
  1540.     else    bptr->first = vpage;
  1541.  
  1542.     vpage->gap_start = 0;
  1543.     vpage->page_len = 0;
  1544.     vpage->where = 'S';
  1545.     vpage->page_num = cnt;
  1546.     ++(bptr->num_pages);
  1547.     return(vpage);
  1548.     }
  1549.  
  1550.  
  1551. /* ------------------------------------------------------------ */
  1552.  
  1553. /* Find a free page. */
  1554.  
  1555. struct phys_page *
  1556. B_PageFindFree()
  1557.     {
  1558.     struct phys_page *ppage;
  1559.     int cnt;
  1560.  
  1561.     cnt = NUM_PHYS_PAGES / 3 + 1;
  1562.     for (ppage = last_phys_page; --cnt > 0 &&
  1563.          (ppage->page_loc == 'L' || ppage->is_mod);
  1564.          ppage = ppage->prev) ;
  1565.  
  1566.     if (cnt <= 0) {
  1567.         BFlush();
  1568.         for (ppage = last_phys_page; ppage != NULL &&
  1569.              (ppage->page_loc == 'L' || ppage->is_mod);
  1570.              ppage = ppage->prev) ;
  1571.         if (ppage == NULL) {
  1572.             DError("Internal paging error");
  1573.             return(NULL);
  1574.             }
  1575.         }
  1576.  
  1577.     if (ppage->page_loc == 'S') {
  1578.         ppage->pptr->where = 'S';
  1579.         ppage->pptr->page_num = ppage->page_num;
  1580.         }
  1581.     return(ppage);
  1582.     }
  1583.  
  1584.  
  1585. /* ------------------------------------------------------------ */
  1586.  
  1587. /* Free the specifed page. */
  1588.  
  1589. void
  1590. B_PageFree(bptr, vpage)
  1591.     struct buffer *bptr;
  1592.     struct virt_page *vpage;
  1593.     {
  1594.     struct phys_page *ppage;
  1595.  
  1596.     if (vpage->next != NULL)
  1597.         vpage->next->prev = vpage->prev;
  1598.     else    bptr->last = vpage->prev;
  1599.     if (vpage->prev != NULL)
  1600.         vpage->prev->next = vpage->next;
  1601.     else    bptr->first = vpage->next;
  1602.  
  1603.     --(bptr->num_pages);
  1604.  
  1605.     if (vpage->where == 'M') {
  1606.         ppage = &pages[vpage->page_num];
  1607.         swap_map[ppage->page_num] = FALSE;
  1608.         pages[vpage->page_num].page_loc = 'M';
  1609.         pages[vpage->page_num].is_mod = FALSE;
  1610.         }
  1611.     else    swap_map[vpage->page_num] = FALSE;
  1612.  
  1613.     free(vpage);
  1614.     }
  1615.  
  1616.  
  1617. /* ------------------------------------------------------------ */
  1618.  
  1619. /* Split the curent (presumably full) page.  AMOUNT is where to split
  1620. it. */
  1621.  
  1622. FLAG
  1623. B_PageSplit(amount)
  1624.     int amount;
  1625.     {
  1626.     struct mark *mptr;
  1627.     struct virt_page *vpage;
  1628.     struct phys_page *ppage;
  1629.  
  1630.     if ((vpage = B_PageAllocate(cbuf, cur_page, cur_page->next)) == NULL)
  1631.         return(FALSE);
  1632.     B_PageToMemory(vpage);
  1633.  
  1634.     ppage = &pages[vpage->page_num];
  1635.     memmove(ppage->page_data, cur_page_start + amount, PAGESIZE - amount);
  1636.  
  1637.     ppage->is_mod = TRUE;
  1638.     cur_is_mod = TRUE;
  1639.     cur_gap_start = cur_page_start + amount;
  1640.     cur_gap_end = cur_page_start + PAGESIZE;
  1641.     cur_page_len = amount;
  1642.     vpage->page_len = PAGESIZE - amount;
  1643.     vpage->gap_start = PAGESIZE - amount;
  1644.  
  1645.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1646.         if (mptr->pptr == cur_page && mptr->mark_offset >= amount) {
  1647.             mptr->pptr = vpage;
  1648.             mptr->mark_offset -= amount;
  1649.             }
  1650.         }
  1651.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1652.         if (mptr->pptr == cur_page && mptr->mark_offset >= amount) {
  1653.             mptr->pptr = vpage;
  1654.             mptr->mark_offset -= amount;
  1655.             }
  1656.         }
  1657.  
  1658.     if (cur_pt_offset >= amount) {
  1659.         B_PageToCurrent(vpage);
  1660.         B_MovePointTo(cur_pt_offset - amount);
  1661.         }
  1662.     return(TRUE);
  1663.     }
  1664.  
  1665.  
  1666. /* ------------------------------------------------------------ */
  1667.  
  1668. /* Make VPAGE the current page. */
  1669.  
  1670. void
  1671. B_PageToCurrent(vpage)
  1672.     struct virt_page *vpage;
  1673.     {
  1674.     struct phys_page *ppage;
  1675.  
  1676.     if (vpage == NULL) {
  1677.         DError("Null page");
  1678.         return;
  1679.         }
  1680.  
  1681.     if (cur_page == vpage) return;
  1682.  
  1683.     if (cur_page != NULL) {
  1684.         cur_page->page_len = cur_page_len;
  1685.         cur_page->gap_start = cur_gap_start - cur_page_start;
  1686.         pages[cur_page->page_num].is_mod = cur_is_mod;
  1687.         }
  1688.  
  1689.     B_PageToMemory(vpage);
  1690.     cur_page = vpage;
  1691.     ppage = &pages[cur_page->page_num];
  1692.     cur_page_start = ppage->page_data;
  1693.     cur_is_mod = ppage->is_mod;
  1694.     cur_page_len = cur_page->page_len;
  1695.     cur_gap_start = cur_page_start + cur_page->gap_start;
  1696.     cur_gap_end = cur_gap_start - cur_page_len + PAGESIZE;
  1697.  
  1698.     if (ppage == first_phys_page) return;
  1699.     if (ppage->next == NULL)
  1700.         last_phys_page = ppage->prev;
  1701.     else    ppage->next->prev = ppage->prev;
  1702.     if (ppage->prev != NULL) ppage->prev->next = ppage->next;
  1703.     ppage->prev = NULL;
  1704.     ppage->next = first_phys_page;
  1705.     first_phys_page->prev = ppage;
  1706.     first_phys_page = ppage;
  1707.     }
  1708.  
  1709.  
  1710. /* ------------------------------------------------------------ */
  1711.  
  1712. /* Make sure that the specified page is swapped into memory. */
  1713.  
  1714. void
  1715. B_PageToMemory(vpage)
  1716.     struct virt_page *vpage;
  1717.     {
  1718.     struct phys_page *ppage;
  1719.  
  1720.     if (vpage->where == 'M') return;
  1721.     ppage = B_PageFindFree();
  1722.     ppage->page_loc = 'S';
  1723.     ppage->page_num = vpage->page_num;
  1724.     ppage->is_mod = FALSE;
  1725.     ppage->pptr = vpage;
  1726.  
  1727.     if (vpage->page_len != 0) {
  1728. #if defined(MSDOS)
  1729.         char huge *tmp = (char huge *)((long)swap_base << 16);
  1730.         BlockGet(ppage->page_data,
  1731.             tmp + (long)ppage->page_num * PAGESIZE, PAGESIZE);
  1732. #endif
  1733. #if defined(UNIX)
  1734.         memmove(ppage->page_data,
  1735.             swap_base + ppage->page_num * PAGESIZE, PAGESIZE);
  1736. #endif
  1737.         }
  1738.  
  1739.     vpage->where = 'M';
  1740.     vpage->page_num = (ppage - pages) / (&pages[1] - &pages[0]);
  1741.     }
  1742.  
  1743.  
  1744. /* ------------------------------------------------------------ */
  1745.  
  1746. /* You are at a ruler line.  Process it. */
  1747.  
  1748. void
  1749. B_RulerLine()
  1750.     {
  1751.     int num;
  1752.     int chr;
  1753.  
  1754.     cbuf->c.fill = 'W';
  1755.     BMoveBy(1);
  1756.     for (;;) {
  1757.         chr = NUL;
  1758.         switch (xtoupper(BGetCharAdv())) {
  1759.  
  1760.         case 'F':
  1761.             cbuf->c.fill = 'F';
  1762.             break;
  1763.  
  1764.         case 'L':
  1765.             BMoveBy(1);
  1766.             num = 0;
  1767.             while (xisdigit(chr = BGetCharAdv())) {
  1768.                 num = num * 10 + chr - '0';
  1769.                 }
  1770.             cbuf->c.left_margin = num;
  1771.             break;
  1772.  
  1773.         case 'N':
  1774.             cbuf->c.fill = 'N';
  1775.             break;
  1776.  
  1777.         case 'R':
  1778.             BMoveBy(1);
  1779.             num = 0;
  1780.             while (xisdigit(chr = BGetCharAdv())) {
  1781.                 num = num * 10 + chr - '0';
  1782.                 }
  1783.             cbuf->c.right_margin = num;
  1784.             break;
  1785.  
  1786.         case 'T':
  1787.             BMoveBy(1);
  1788.             num = 0;
  1789.             while (xisdigit(chr = BGetCharAdv())) {
  1790.                 num = num * 10 + chr - '0';
  1791.                 }
  1792.             cbuf->c.tab_spacing = num;
  1793.             break;
  1794.  
  1795.         case 'W':
  1796.             cbuf->c.fill = 'W';
  1797.             break;
  1798.  
  1799.         default:
  1800.             WFixup(&(cbuf->c));
  1801.             return;
  1802.             /*break;*/
  1803.             }
  1804.         if (chr == NL) break;
  1805.         }
  1806.     WFixup(&(cbuf->c));
  1807.     }
  1808.  
  1809.  
  1810. /* ------------------------------------------------------------ */
  1811.  
  1812. /* Set the modified flag to NEWFLAG. */
  1813.  
  1814. void
  1815. B_SetScreenMarks(newflag)
  1816.     FLAG newflag;
  1817.     {
  1818.     struct window *wptr;
  1819.  
  1820.     for (wptr = windows; wptr < &windows[NUMWINDOWS]; wptr++) {
  1821.         if (wptr->visible) B_SetScreenMarks2(wptr, newflag);
  1822.         }
  1823.     }
  1824.  
  1825.  
  1826. /* ------------------------------------------------------------ */
  1827.  
  1828. /* Set one windows' modified flags. */
  1829.  
  1830. void
  1831. B_SetScreenMarks2(wptr, newflag)
  1832.     struct window *wptr;
  1833.     FLAG newflag;
  1834.     {
  1835.     struct mark *mptr;
  1836.     struct mark *botmptr;
  1837.     struct mark *topmptr;
  1838.  
  1839.     botmptr = &screenmarks[wptr->bot];
  1840.     topmptr = &screenmarks[wptr->top];
  1841.  
  1842.     for (mptr = topmptr; mptr <= botmptr &&
  1843.         mptr->pptr != cur_page; ++mptr) ;
  1844.  
  1845.     if (mptr->bptr != cbuf) {
  1846.         mptr->is_mod = TRUE;
  1847.         }
  1848.     else if (mptr > botmptr) {
  1849.         for (mptr = topmptr; mptr <= botmptr &&
  1850.             (mptr->bptr != cbuf || BIsAfterMark(mptr));
  1851.             ++mptr) ;
  1852.         if (mptr > topmptr) {
  1853.             while ((--mptr)->bptr != cbuf) ;
  1854.             mptr->is_mod = TRUE;
  1855.             }
  1856.         }
  1857.     else    {
  1858.         while (mptr->pptr == cur_page &&
  1859.              mptr->mark_offset <= cur_pt_offset &&
  1860.              mptr <= botmptr)
  1861.             ++mptr;
  1862.  
  1863.         if (--mptr >= topmptr) mptr->is_mod = TRUE;
  1864.  
  1865.         if (newflag) {
  1866.             while (mptr > topmptr && mptr->pptr == cur_page &&
  1867.                  mptr->mark_offset == cur_pt_offset) {
  1868.                 (--mptr)->is_mod = TRUE;
  1869.                 }
  1870.             }
  1871.         }
  1872.     }
  1873.  
  1874.  
  1875. /* ------------------------------------------------------------ */
  1876.  
  1877. /* Check buffer data structures for consistency. */
  1878.  
  1879. #if defined(DEBUGGING_CODE)
  1880. void B_XVirtPage();
  1881.  
  1882. void
  1883. B_XDebug()
  1884.     {
  1885.     struct buffer *bptr;
  1886.     struct mark *mptr;
  1887.     struct virt_page *vptr;
  1888.     char buf[1000];
  1889.     int cnt;
  1890.     int cnt2;
  1891.  
  1892. /* check buffers */
  1893.     for (cnt = 0; cnt < NUMBUFFERS; cnt++) {
  1894.         bptr = &buffers[cnt];
  1895.         if (bptr->num_pages == 0) continue;    /* free */
  1896.  
  1897.         if (*bptr->fname == NUL) {
  1898.             xsprintf(buf, "buffer %d has no filename", cnt);
  1899.             DError(buf);
  1900.             }
  1901.         if (strlen(bptr->fname) > FNAMEMAX) {
  1902.             xsprintf(buf, "buffer %d has invalid filename", cnt);
  1903.             DError(buf);
  1904.             }
  1905.  
  1906.         for (cnt2 = 0; cnt2 < MAXMARK; cnt2++) {
  1907.             if (bptr->mptr == &marks[cnt2]) break;
  1908.             }
  1909.         if (cnt2 >= MAXMARK) {
  1910.             xsprintf(buf, "buffer %d has invalid mark", cnt);
  1911.             DError(buf);
  1912.             }
  1913.  
  1914.         B_XVirtPage(bptr->first, "buf first", cnt);
  1915.         B_XVirtPage(bptr->last, "buf last", cnt);
  1916.         B_XVirtPage(bptr->point_page, "buf point_page", cnt);
  1917.         for (vptr = bptr->first, cnt2 = 0; vptr != bptr->last;
  1918.              vptr = vptr->next, cnt2++) {
  1919.             B_XVirtPage(vptr, "buf page", cnt2);
  1920.             }
  1921.  
  1922.         if (bptr->point_offset < 0 || bptr->point_offset >= PAGESIZE) {
  1923.             xsprintf(buf, "buffer %d has invalid offset %d", cnt,
  1924.                 bptr->point_offset);
  1925.             DError(buf);
  1926.             }
  1927.         if (bptr->point_page->page_len &&
  1928.              bptr->point_offset > bptr->point_page->page_len + 1) {
  1929.             xsprintf(buf, "buffer %d has invalid offset %d of %d",
  1930.                 cnt, bptr->point_offset,
  1931.                 bptr->point_page->page_len);
  1932.             DError(buf);
  1933.             }
  1934.  
  1935.         if (bptr->num_pages < 0 || bptr->num_pages >= num_swap) {
  1936.             xsprintf(buf, "buffer %d has invalid num of pages %d",
  1937.                 cnt, bptr->num_pages);
  1938.             DError(buf);
  1939.             }
  1940.         }
  1941.  
  1942. /* check marks */
  1943.  
  1944.     for (cnt = 0; cnt < MAXMARK; cnt++) {
  1945.         mptr = &marks[cnt];
  1946.         if (mptr->pptr == NULL) continue;
  1947.         if (BIsFree(mptr->bptr)) continue;
  1948.  
  1949.         B_XVirtPage(mptr->pptr, "mark pptr", cnt);
  1950.  
  1951.         if (mptr->mark_offset < 0 || mptr->mark_offset >= PAGESIZE) {
  1952.             xsprintf(buf, "mark %d has invalid offset %d", cnt,
  1953.                 mptr->mark_offset);
  1954.             DError(buf);
  1955.             }
  1956.         if (mptr->pptr->page_len > 0 &&
  1957.              mptr->mark_offset > mptr->pptr->page_len + 1) {
  1958.             xsprintf(buf, "mark %d has invalid offset %d of %d",
  1959.                 cnt, mptr->mark_offset, mptr->pptr->page_len);
  1960.             DError(buf);
  1961.             }
  1962.         }
  1963.  
  1964. /* screen marks */
  1965.  
  1966.     for (cnt = 0; cnt < MAXSMARK - 1; cnt++) {
  1967.         mptr = &screenmarks[cnt];
  1968.         if (mptr->pptr == NULL) continue;
  1969.         if (BIsFree(mptr->bptr)) continue;
  1970.  
  1971.         B_XVirtPage(mptr->pptr, "scrnmark pptr", cnt);
  1972.  
  1973.         if (mptr->mark_offset < 0 || mptr->mark_offset >= PAGESIZE) {
  1974.             xsprintf(buf, "smark %d has invalid offset %d", cnt,
  1975.                 mptr->mark_offset);
  1976.             DError(buf);
  1977.             }
  1978.         if (mptr->pptr->page_len > 0 &&
  1979.              mptr->mark_offset > mptr->pptr->page_len + 1) {
  1980.             xsprintf(buf, "smark %d has invalid offset %d of %d",
  1981.                 cnt, mptr->mark_offset, mptr->pptr->page_len);
  1982.             DError(buf);
  1983.             }
  1984.         }
  1985.     }
  1986.  
  1987. void
  1988. B_XVirtPage(vptr, descr, cnt)
  1989.     struct virt_page *vptr;
  1990.     char *descr;
  1991.     int cnt;
  1992.     {
  1993.     char buf[1000];
  1994. /*
  1995.     struct virt_page *next;
  1996.     struct virt_page *prev;
  1997. */
  1998.     if (vptr->where != 'L' && vptr->where != 'M' && vptr->where != 'S') {
  1999.         xsprintf(buf, "virt page %s %d has invalid loc %c",
  2000.             descr, cnt, vptr->where);
  2001.         DError(buf);
  2002.         }
  2003.  
  2004.     if (vptr->page_num < 0 || vptr->page_num > num_swap) {
  2005.         xsprintf(buf, "virt page %s %d has invalid num %d",
  2006.             descr, cnt, vptr->page_num);
  2007.         DError(buf);
  2008.         }
  2009.  
  2010.     if (vptr->page_len < 0 || vptr->page_len > PAGESIZE) {
  2011.         xsprintf(buf, "virt page %s %d has invalid page size %d",
  2012.             descr, cnt, vptr->page_len);
  2013.         DError(buf);
  2014.         }
  2015.  
  2016.     if (vptr->gap_start < 0 ||
  2017.          (vptr->page_len > 0 && vptr->gap_start > vptr->page_len)) {
  2018.         xsprintf(buf, "virt page %s %d has invalid gap start %d",
  2019.             descr, cnt, vptr->gap_start);
  2020.         DError(buf);
  2021.         }
  2022.     }
  2023. struct buffer *cbuf;            /* the curent buffer */
  2024. struct mark *mark;            /* the current mark */
  2025. static struct virt_page *cur_page;    /* virtual page */
  2026. static int cur_pt_offset;        /* point offset */
  2027. static int cur_page_len;        /* page length */
  2028. static char *cur_cptr;            /* actual character */
  2029. static char *cur_page_start;        /* start of the page */
  2030. static char *cur_gap_start;        /* position of the gap */
  2031. static char *cur_gap_end;
  2032. static FLAG cur_is_mod;            /* is modified (dirty) */
  2033. static int cur_col = -1;        /* current column position */
  2034. static int savecol;
  2035. struct mark *getmark;
  2036. static struct phys_page *first_phys_page;  /* LRU chain of pages in memory */
  2037. static struct phys_page *last_phys_page;
  2038. #define SWAPMAPSIZE    ((long)SWAPMAX * 1024 / PAGESIZE)
  2039. static char swap_map[SWAPMAPSIZE];    /* swap file in use flags */
  2040. #endif
  2041.  
  2042. /* end of BUF.C -- Buffer Managment */
  2043.